<template>
  <div 
    class="timeLineContainer" 
    ref="timeLineContainer" 
    :style="{
      backgroundColor: backgroundColor,
    }" 
    @touchstart="onTouchstart" 
    @touchmove="onTouchmove" 
    @mousedown="onMousedown" 
    @mouseout="onMouseout"
    @mousemove="onMousemove" 
    @mouseleave="onMouseleave"
    @mouseup="mouseup"
  >
    <canvas 
      class="canvas" 
      ref="canvas" 
      @mousewheel.stop.prevent="onMouseweel"
    ></canvas>
    <div 
      class="windowList" 
      ref="windowList" 
      v-if="showWindowList && windowList && windowList.length > 1"
      @scroll="onWindowListScroll"
    >
      <WindowListItem 
        v-for="(item, index) in windowListInner" 
        ref="WindowListItem" 
        :key="index" 
        :index="index"
        :data="item" 
        :totalMS="totalMS" 
        :startTimestamp="startTimestamp" 
        :width="width" 
        :active="item.active"
        @click_window_timeSegments="triggerClickWindowTimeSegments" 
        @click="toggleActive(index)"
      ></WindowListItem>
    </div>
  </div>
</template>

<script>
import dayjs from "dayjs";
import WindowListItem from "./WindowListItem";
import {
  ONE_HOUR_STAMP,
  ZOOM,
  ZOOM_WIDTH,
  ZOOM_HOUR_GRID,
  ZOOM_DATE_SHOW_RULE,
  MOBILE_ZOOM_HOUR_GRID,
  MOBILE_ZOOM_DATE_SHOW_RULE
} from "./constant";

/**
 * @Date: 2021-01-19 20:15:07
 * @Desc: 时间轴组件
 */
export default {
  name: "TimeLine",
  components: {
    WindowListItem
  },
  props: {
    // 时间范围
    duration: {
      type: Number,
      default: 0
    },
    // 初始时间，中点所在的时间，默认为当天0点
    initTime: {
      type: [Number, String],
      default: ""
    },
    // 显示预览的时间范围，即中间刻度所允许的时间范围
    /*
      {
        start: '2020-12-19 18:30:00',// 允许显示的最小时间
        end: '2021-01-20 10:0:00'// 允许显示的最大时间
      }
    */
    timeRange: {
      type: Object,
      default() {
        return {};
      }
    },
    // 初始的时间分辨率
    initZoomIndex: {
      type: Number,
      default: 5 // 24小时
    },
    // 是否显示中间的竖线
    showCenterLine: {
      type: Boolean,
      default: true
    },
    // 中间竖线的样式
    centerLineStyle: {
      type: Object,
      default() {
        return {
          width: 2,
          color: "#fff"
        };
      }
    },
    // 日期时间文字颜色
    textColor: {
      type: String,
      default: "rgba(151,158,167,1)"
    },
    // 鼠标滑过显示的时间文字颜色
    hoverTextColor: {
      type: String,
      default: "rgb(194, 202, 215)"
    },
    // 时间线段颜色
    lineColor: {
      type: String,
      default: "rgba(151,158,167,1)"
    },
    // 时间线段高度占时间轴高度的比例
    lineHeightRatio: {
      type: Object,
      default() {
        return {
          date: 0.3, // 0点时的日期线段高度
          time: 0.2, // 显示时间的线段高度
          none: 0.1, // 不显示时间的线段高度
          hover: 0.3 // 鼠标滑过时显示的时间段高度
        };
      }
    },
    // 鼠标滑过时是否显示实时所在的时间
    showHoverTime: {
      type: Boolean,
      default: true
    },
    // 格式化鼠标滑过时间
    hoverTimeFormat: {
      type: Function
    },
    // 要显示的时间颜色段
    /*
      {
        beginTime: new Date('2021-01-19 14:30:00').getTime(),// 起始时间戳
        endTime: new Date('2021-01-20 18:00:00').getTime(),// 结束时间戳
        color: '#FA3239',// 颜色
        startRatio: 0.65,// 高度的起始比例，即top=时间轴高度*startRatio
        endRatio: 0.9// 高度的结束比例，即bottom=时间轴高度*endRatio
      }
    */
    timeSegments: {
      type: Array,
      default: () => []
    },
    // 时间轴背景颜色
    backgroundColor: {
      type: String,
      default: "#262626"
    },
    // 是否允许切换分辨率
    enableZoom: {
      type: Boolean,
      default: true
    },
    // 是否允许拖动
    enableDrag: {
      type: Boolean,
      default: true
    },
    // 窗口列表，如果窗口数量大于1的话可以配置此项，会显示和窗口对应数量的时间轴，只有一个窗口的话请直接使用基本时间轴
    /*
      {
        timeSegments: [// 时间段
          {
            beginTime: new Date('2021-01-19 14:30:00').getTime(),// 起始时间戳
            endTime: new Date('2021-01-20 18:00:00').getTime(),// 结束时间戳
            color: '#FA3239',// 颜色
            startRatio: 0.65,// 高度的起始比例，即top=时间轴高度*startRatio
            endRatio: 0.9// 高度的结束比例，即bottom=时间轴高度*endRatio
          }
        ],
        // 你的其他附加信息...
      }
    */
    windowList: {
      type: Array,
      default() {
        return [];
      }
    },
    // 当显示windowList时的基础时间轴高度
    baseTimeLineHeight: {
      type: Number,
      default: 50
    },
    // 初始选中的窗口时间轴
    initSelectWindowTimeLineIndex: {
      type: Number,
      default: -1
    },
    // 是否是手机端
    isMobile: {
      type: Boolean,
      default: false
    },
    // 鼠标按下和松开的距离小于该值认为是点击事件
    maxClickDistance: {
      type: Number,
      default: 3
    },
    // 绘制时间段时对计算出来的坐标进行四舍五入，可以防止相连的时间段绘制出来有间隔的问题
    roundWidthTimeSegments: {
      type: Boolean,
      default: true
    },
    // 自定义显示哪些时间
    customShowTime: {
      type: Function
    },
    // 0点处是否显示日期
    showDateAtZero: {
      type: Boolean,
      default: true
    },
    // 扩展ZOOM列表，这个数组的数据会追加到内部的ZOOM数组，对应的zoomIndex往后累加即可，内部一共有11个zoom，那么你追加了一项，对应的zoomIndex为11，因为是从零开始计数
    // 数组类型，数组的每一项为：
    /*
      {
        zoom: 26,// 时间分辨率，整个时间轴表示的时间范围，单位：小时
        zoomHourGrid: 0.5,// 时间分辨率对应的每格小时数，即时间轴上最小格代表多少小时
        mobileZoomHourGrid: 2, // 手机模式下时间分辨率对应的每格小时数，如果不用适配手机端，可以不用设置
      }
    */
    // 同时你需要传递customShowTime属性来自定义控制时间显示，否则会报错，因为内置的规则只有11个
    extendZOOM: {
      type: Array,
      default() {
        return [];
      }
    },
    // 格式化时间轴显示时间
    formatTime: {
      type: Function
    }
  },
  data() {
    return {
      width: 0,
      height: 0,
      ctx: null,
      currentZoomIndex: 0,
      currentTime: 0,
      startTimestamp: 0,
      mousedown: false,
      mousedownX: 0,
      mousedownY: 0,
      mousedownCacheStartTimestamp: 0,
      showWindowList: false,
      windowListInner: [],
      mousemoveX: -1,
      watchTimeList: [],
      // 输入框
      points: [],
    };
  },
  computed: {
    // 整个时间轴所代表的毫秒数
    totalMS() {
      return ZOOM[this.currentZoomIndex] * ONE_HOUR_STAMP * this.duration;
    },
    // 时间范围的时间戳表示
    timeRangeTimestamp() {
      let t = {};
      if (this.timeRange.start) {
        t.start =
          typeof this.timeRange.start === "number"
            ? this.timeRange.start
            : new Date(this.timeRange.start).getTime();
      }
      if (this.timeRange.end) {
        t.end =
          typeof this.timeRange.end === "number"
            ? this.timeRange.end
            : new Date(this.timeRange.end).getTime();
      }
      return t;
    },
    ACT_ZOOM_HOUR_GRID() {
      return this.isMobile ? MOBILE_ZOOM_HOUR_GRID : ZOOM_HOUR_GRID;
    },
    ACT_ZOOM_DATE_SHOW_RULE() {
      return this.isMobile ? MOBILE_ZOOM_DATE_SHOW_RULE : ZOOM_DATE_SHOW_RULE;
    },
    // 年月模式
    yearMonthMode() {
      return this.currentZoomIndex === 9;
    },
    // 年模式
    yearMode() {
      return this.currentZoomIndex === 10;
    }
  },
  watch: {
    timeSegments: {
      deep: true,
      handler: "reRender"
    },
    initTime: {
      handler: function (e) {
        if(e) {
          this.startTimestamp = -e * ZOOM_WIDTH[this.currentZoomIndex];
          this.onMouseout();
        }
      },
      immediate: true,
      deep: true
    }
  },
  created() {
    this.extendZOOM.forEach(item => {
      ZOOM.push(item.zoom);
      ZOOM_HOUR_GRID.push(item.zoomHourGrid);
      MOBILE_ZOOM_HOUR_GRID.push(item.mobileZoomHourGrid);
    });
  },
  mounted() {
    this.setInitData();
    this.init();
    this.draw();

    // this.onMouseup = this.onMouseup.bind(this)
    // this.onResize = this.onResize.bind(this)
    // this.onTouchend = this.onTouchend.bind(this)
    // if (this.isMobile) {
    //   window.addEventListener('touchend', this.onTouchend)
    // } else {
    //   window.addEventListener('mouseup', this.onMouseup)
    // }
    // window.addEventListener('resize', this.onResize)
  },
  // beforeDestroy() {
  //   if (this.isMobile) {
  //     window.removeEventListener('touchend', this.onTouchend)
  //   } else {
  //     window.removeEventListener('mouseup', this.onMouseup)
  //   }
  //   window.removeEventListener('resize', this.onResize)
  // },
  methods: {
    /**
     * @Date: 2024-12-16 16:30:00
     * @Desc: 点击显示输入框
     */
    drawInput() {
      
      this.ctx.beginPath();
      const startX = this.points[0].x;
      const startY = this.points[0].y;
			
			const textarea = document.createElement('textarea'); // 创建一个多行输入框元素 
			const canvasRect = this.$refs.canvas.getBoundingClientRect(); // 获取画布的位置信息
			const fontSize = 30;
			
			textarea.rows = 10;
            textarea.style.position = 'absolute';
			textarea.style.left = (canvasRect.left + startX) - 10 + 'px'; // 计算输入框的左边距（最后-10是为了让光标能显示在鼠标前面一点点）
			textarea.style.top = (canvasRect.top + startY) + 'px'; // 计算输入框的上边距
			textarea.style.border = 'none';
			textarea.style.background = 'transparent';
			textarea.style.font = fontSize+'px 微软雅黑';
			textarea.style.color = '#000';
			textarea.style.outline = 'none';
			textarea.style.padding = '0';
			textarea.style.margin = '0';
			textarea.style.width = 'auto';
			textarea.style.height = 'auto';
			textarea.style.resize = 'none';
			textarea.style.overflow = 'hidden';
			textarea.style.zIndex = '100';
			// 监听失去焦点事件
			textarea.addEventListener('blur', () => {
				const text = textarea.value;
				if(text.length > 0){
					this.ctx.font = fontSize+'px 微软雅黑';
					this.ctx.fillStyle = '#000';
					const lines = text.split('\n'); // 将输入的文本按换行符分割成多行
					let y = startY;
					lines.forEach((line) => {
						this.ctx.fillText(line, startX, y); // 在画布上绘制每一行文字
						y += (fontSize+5); // 每行文字的垂直间距为35像素（这个一般要根据字体大小进行设置，我设置的是字体大小+5比较合适）
					});
				}
				document.body.removeChild(textarea); // 移除输入框元素
			});
			document.body.appendChild(textarea); // 将输入框元素添加到页面中
			textarea.focus(); // 让输入框获得焦点
      this.ctx.stroke();
      
    },
    /**
     * @Date: 2021-01-19 20:20:45
     * @Desc: 设置初始数据
     */
    setInitData() {
      // 内部窗口列表数据
      this.windowListInner = this.windowList.map((item, index) => {
        return {
          ...item,
          active: this.initSelectWindowTimeLineIndex === index
        };
      });
      // 必须先设置currentZoomIndex
      // 初始时间分辨率
      this.currentZoomIndex =
        this.initZoomIndex >= 0 && this.initZoomIndex < ZOOM.length
          ? this.initZoomIndex
          : 5;
      // 初始当前时间
      this.startTimestamp = this.initTime
        ? typeof this.initTime === "number"
          ? this.initTime
          : Number(this.initTime)
        : this.initTime;
      // this.fixStartTimestamp()
    },

    /**
     * @Date: 2021-01-20 16:01:21
     * @Desc: 根据时间范围检查并修正起始时间
     */
    fixStartTimestamp() {
      let ct = this.startTimestamp;
      if (this.timeRangeTimestamp.start && ct < this.timeRangeTimestamp.start) {
        this.startTimestamp = this.timeRangeTimestamp.start; // - hfms
      }
      if (this.timeRangeTimestamp.end && ct > this.timeRangeTimestamp.end) {
        this.startTimestamp = this.timeRangeTimestamp.end; // - hfms
      }
    },

    /**
     * @Date: 2020-04-14 09:20:22
     * @Desc: 初始化
     */
    init() {
      let {
        width,
        height
      } = this.$refs.timeLineContainer.getBoundingClientRect();
      this.width = width;
      this.height =
        this.windowList.length > 1 ? this.baseTimeLineHeight : height;
      this.$refs.canvas.width = this.width;
      this.$refs.canvas.height = this.height;
      this.ctx = this.$refs.canvas.getContext("2d");
      this.showWindowList = true;
    },

    /**
     * @Date: 2020-04-14 09:27:18
     * @Desc: 绘制方法
     */
    draw() {
      //绘制竖线
      this.drawMiddleLine();
      //绘制时间刻度
      this.addGraduations();
      // 顺序很重要，不然层级不对
      this.drawEachTimeSegments();

      this.currentTime = this.startTimestamp; // + this.totalMS / 2
      this.$emit("timeChange", this.currentTime);

      // 通知窗口时间轴渲染
      try {
        if (this.$refs.WindowListItem) {
          this.$refs.WindowListItem.forEach(item => {
            item.draw();
          });
        }
      } catch (error) {
        console.log(error);
      }

      // 更新观察的时间位置
      this.updateWatchTime();
    },

    /**
     * @Date: 2021-01-21 10:50:11
     * @Desc:  更新观察的时间位置
     */
    updateWatchTime() {
      this.watchTimeList.forEach(item => {
        // 当前不在显示范围内
        if (
          item.time < this.startTimestamp ||
          item.time > this.startTimestamp + this.totalMS
        ) {
          item.callback(-1, -1);
        } else {
          // 在范围内
          let x =
            (item.time - this.startTimestamp) * (this.width / this.totalMS);
          let y = 0;
          let { left, top } = this.$refs.canvas.getBoundingClientRect();
          if (
            item.windowTimeLineIndex !== -1 &&
            this.windowList.length > 1 &&
            item.windowTimeLineIndex >= 0 &&
            item.windowTimeLineIndex < this.windowList.length
          ) {
            let rect = this.$refs.WindowListItem[
              item.windowTimeLineIndex
            ].getRect();
            y = rect ? rect.top : top;
          } else {
            y = top;
          }
          item.callback(x + left, y);
        }
      });
    },

    /**
     * 绘制中间的竖线
     */
    drawMiddleLine() {
      if (!this.showCenterLine) {
        return;
      }
      this.ctx.beginPath();
      let { width, color } = this.centerLineStyle;
      let x = this.width / 2;
      this.drawLine(x, 0, x, this.height, width, color);
    },

    /**
     * 绘制时间刻度
     */
    addGraduations() {
      this.ctx.beginPath();
      // 时间轴总格数
      let gridNum =
        this.duration / this.ACT_ZOOM_HOUR_GRID[this.currentZoomIndex];
      // 一格多少毫秒
      // let msPerGrid = this.ACT_ZOOM_HOUR_GRID[this.currentZoomIndex] * ONE_HOUR_STAMP;
      // 每格间距，一格多少像素宽
      let pxPerGrid = ZOOM_WIDTH[this.currentZoomIndex];
      // 中间距离
      let centerOffset = this.width / 2;
      for (let i = 0; i < gridNum; i++) {
        let x = centerOffset + i * pxPerGrid + this.startTimestamp;
        let h = this.height * 0.3;
        this.ctx.fillStyle = this.textColor;
        this.ctx.fillText(
          this.formatDuration(
            i * this.ACT_ZOOM_HOUR_GRID[this.currentZoomIndex]
          ),
          x - 20,
          h + 15
        );
        this.drawLine(x, 0, x, h, 1, this.lineColor);
        // console.log(1111111,x, this.startTimestamp)
      }
    },

    /**
     *
     * 绘制时间段色块
     */
    drawEachTimeSegments() {
      this.ctx.beginPath();
      // 时间轴总格数
      // let gridNum = this.duration / this.ACT_ZOOM_HOUR_GRID[this.currentZoomIndex];
      // 一格多少毫秒
      // let msPerGrid = this.ACT_ZOOM_HOUR_GRID[this.currentZoomIndex] * ONE_HOUR_STAMP;
      // 每格间距，一格多少像素宽
      let pxPerGrid = ZOOM_WIDTH[this.currentZoomIndex];
      // 中间距离
      let centerOffset = this.width / 2;
      this.timeSegments.forEach(item => {
        this.ctx.beginPath();
        let x = centerOffset + (item.beginTime * pxPerGrid) + this.startTimestamp;
        // 避免时间段小于1px绘制不出来
        let w = (item.endTime - item.beginTime) * pxPerGrid;
        this.ctx.fillStyle = item.color;
        this.ctx.fillRect(
          x,
          this.height * 0.6,
          w,
          this.height / 3
        );
        this.ctx.fillStyle = item.textColor;
        this.ctx.fillText(
          item.text,
          x + 10,
          this.height * 0.8,
          w
        );
        this.ctx.stroke();
      });
    },
    // 判断是否需要显示该时间
    checkShowTime(date) {
      if (this.customShowTime) {
        let res = this.customShowTime(date, this.currentZoomIndex);
        if (res === true) {
          return true;
        } else if (res === false) {
          return false;
        }
      }
      return this.ACT_ZOOM_DATE_SHOW_RULE[this.currentZoomIndex](date);
    },

    /**
     * @Date: 2020-04-14 14:29:40
     * @Desc: 鼠标按下事件
     */
    onMousedown(e) {
      if (this.isMobile) {
        return;
      }
      this.onPointerdown(e);
    },

    // 按下事件
    onPointerdown(e) {
      let pos = this.getClientOffset(e);
      this.mousedownX = pos[0];
      this.mousedownY = pos[1];
      this.mousedown = true;
      this.mousedownCacheStartTimestamp = this.startTimestamp;
      this.$emit("mousedown", e);
    },

    /**
     * @Date: 2020-04-14 14:38:30
     * @Desc: 鼠标松开
     */
    onMouseup(e) {
      if (this.isMobile) {
        return;
      }
      this.onPointerup(e);
    },

    // 松开事件
    onPointerup(e) {
      // 触发click事件
      let pos = this.getClientOffset(e);
      const reset = () => {
        this.mousedown = false;
        this.mousedownX = 0;
        this.mousedownY = 0;
        this.mousedownCacheStartTimestamp = 0;
      };
      this.points = [{x: pos[0], y: pos[1]}];
      // this.drawInput();
      // 点击发送事件
      if(pos[0] == this.mousedownX && pos[1] == this.mousedownY) {
        this.onClick(...pos);
      }
      if (
        Math.abs(pos[0] - this.mousedownX) <= this.maxClickDistance &&
        Math.abs(pos[1] - this.mousedownY) <= this.maxClickDistance
      ) {
        reset();
        // this.onClick(...pos);
        return;
      }
      if (this.mousedown && this.enableDrag) {
        reset();
        const PX_PER_MS = ZOOM_WIDTH[this.currentZoomIndex];
        this.$emit("dragTimeChange", Math.abs(this.currentTime)/PX_PER_MS);
      } else {
        reset();
      }
      this.$emit("mouseup", e);
    },

    /**
     * @Date: 2020-04-14 14:17:02
     * @Desc: 鼠标移动事件
     */
    onMousemove(e) {
      if (this.isMobile) {
        return;
      }
      this.onPointermove(e);
    },

    // 移动事件
    onPointermove(e) {
      let x = this.getClientOffset(e)[0];
      this.mousemoveX = x;
      // 按下拖动
      if (this.mousedown && this.enableDrag) {
        this.drag(x);
      } else if (this.showHoverTime) {
        // 未按下显示鼠标所在时间
        this.hoverShow(x);
      }
    },

    /**
     * @Date: 2021-01-21 10:40:37
     * @Desc: 鼠标移出事件
     */
    onMouseleave() {
      this.mousemoveX = -1;
      // this.onPointerup();
    },
    mouseup(e) {
      this.onPointerup(e);
    },

    /**
     * 按下拖动
     */
    drag(x) {
      if (!this.enableDrag) {
        return;
      }
      const PX_PER_MS = ZOOM_WIDTH[this.currentZoomIndex];
      let diffX = (x - this.mousedownX) / PX_PER_MS;
      if (this.startTimestamp) {
        this.startTimestamp += diffX;
      } else {
        this.startTimestamp = diffX;
      }
      if (this.startTimestamp * PX_PER_MS > 0) {
        this.startTimestamp = 0;
      }
      if (Math.abs(this.startTimestamp) > this.timeRange.end * PX_PER_MS) {
        this.startTimestamp = -this.timeRange.end * PX_PER_MS;
      }
      // console.log('滑动距离', x, this.mousedownX, PX_PER_MS, this.startTimestamp, diffX);
      this.clearCanvas(this.width, this.height);
      this.draw();
    },

    /**
     * @Date: 2021-01-20 15:29:52
     * @Desc: 未按下显示鼠标所在时间
     */
    hoverShow(x, noDraw) {
      const PX_PER_MS = this.width / this.totalMS; // px/ms
      let time = this.startTimestamp + x / PX_PER_MS;
      if (!noDraw) {
        this.clearCanvas(this.width, this.height);
        this.draw();
      }
      let h =
        this.height *
        (this.lineHeightRatio.hover === undefined
          ? 0.3
          : this.lineHeightRatio.hover);
      this.drawLine(x, 0, x, h, 1, this.lineColor);
      this.ctx.fillStyle = this.hoverTextColor;
      let t = this.hoverTimeFormat
        ? this.hoverTimeFormat(time)
        : dayjs(time).format("YYYY-MM-DD HH:mm:ss");
      let w = this.ctx.measureText(t).width;
      this.ctx.fillText(t, x - w / 2, h + 20);
    },

    /**
     * @Date: 2020-04-14 14:28:48
     * @Desc: 鼠标移出事件
     */
    onMouseout() {
      this.clearCanvas(this.width, this.height);
      this.draw();
    },

    /**
     * @Date: 2020-04-14 15:14:12
     * @Desc: 鼠标滚动
     */
    onMouseweel(event) {
      console.log(event);
      // if (!this.enableZoom) {
      //   return
      // }
      // let e = window.event || event
      // let delta = Math.max(-1, Math.min(1, e.wheelDelta || -e.detail))
      // if (delta < 0) {
      //   if (this.currentZoomIndex + 1 >= ZOOM.length - 1) {
      //     this.currentZoomIndex = ZOOM.length - 1
      //   } else {
      //     this.currentZoomIndex++
      //   }
      // } else if (delta > 0) {
      //   // 放大
      //   if (this.currentZoomIndex - 1 <= 0) {
      //     this.currentZoomIndex = 0
      //   } else {
      //     this.currentZoomIndex--
      //   }
      // }
      // this.$emit('setZoom', this.currentZoomIndex)
      // this.clearCanvas(this.width, this.height)
      // this.startTimestamp = this.currentTime - this.totalMS / 2 // 当前时间-新的时间范围的一半
      // this.draw()
    },

    /**
     * @Date: 2021-01-20 16:22:04
     * @Desc: 点击事件
     */
    onClick(x, y) {
      console.log('点击了', x, y);
      const PX_PER_MS = this.width / this.totalMS; // px/ms
      let time = this.startTimestamp + x / PX_PER_MS;
      let date = dayjs(time).format("YYYY-MM-DD HH:mm:ss");
      let timeSegments = this.getClickTimeSegments(x, y);
      if (timeSegments && timeSegments.length > 0) {
        this.$emit("click_timeSegments", timeSegments, time, date, x);
      } else {
        this.onCanvasClick(time, date, x);
      }
    },

    /**
     * 检测当前是否点击了某个时间段
     */
    getClickTimeSegments(x, y) {
      let inItems = [];
      this.drawEachTimeSegments(item => {
        if (this.ctx.isPointInPath(x, y)) {
          inItems.push(item);
        }
      }, true);
      return inItems;
      
    },

    /**
     * 获取鼠标相当于时间轴的距离
     */
    getClientOffset(e) {
      if (!this.$refs.timeLineContainer || !e) {
        return [0, 0];
      }
      let { left, top } = this.$refs.timeLineContainer.getBoundingClientRect();
      return [e.clientX - left, e.clientY - top];
    },

    /**
     * 清除画布
     */
    clearCanvas(w, h) {
      if(this.ctx)this.ctx.clearRect(0, 0, w, h);
    },

    /**
     * 时间格式化
     */
    graduationTitle(datetime) {
      let time = dayjs(datetime);
      let res = "";
      if (this.formatTime) {
        res = this.formatTime(time);
      }
      if (res) {
        return res;
      }
      if (this.yearMode) {
        return time.format("YYYY");
      } else if (this.yearMonthMode) {
        return time.format("YYYY-MM");
      } else if (
        time.hour() === 0 &&
        time.minute() === 0 &&
        time.millisecond() === 0
      ) {
        return time.format("MM-DD");
      } else {
        return time.format("HH:mm");
      }
    },

    /**
     * 绘制线段
     */
    drawLine(x1, y1, x2, y2, lineWidth = 1, color = "#fff") {
      this.ctx.beginPath();
      this.ctx.strokeStyle = color;
      this.ctx.lineWidth = lineWidth;
      this.ctx.moveTo(x1, y1);
      this.ctx.lineTo(x2, y2);
      this.ctx.stroke();
    },

    /**
     * @Date: 2021-01-20 15:57:11
     * @Desc: 重新渲染
     */
    reRender() {
      this.$nextTick(() => {
        this.clearCanvas(this.width, this.height);
        this.reset();
        this.setInitData();
        this.init();
        this.draw();
      });
    },

    /**
     * @Date: 2021-01-20 16:07:53
     * @Desc: 复位
     */
    reset() {
      this.width = 0;
      this.height = 0;
      this.ctx = null;
      this.currentZoomIndex = 0;
      this.currentTime = 0;
      this.startTimestamp = 0;
      this.mousedown = false;
      this.mousedownX = 0;
      this.mousedownCacheStartTimestamp = 0;
    },

    /**
     * @Date: 2021-01-20 15:57:26
     * @Desc: 设置当前时间
     */
    setTime(t) {
      if (this.mousedown) {
        return;
      }
      let ts = typeof t === "number" ? t : new Date(t).getTime();
      this.startTimestamp = ts - this.totalMS / 2;
      this.fixStartTimestamp();
      this.clearCanvas(this.width, this.height);
      this.draw();
      if (this.mousemoveX !== -1 && !this.isMobile) {
        this.hoverShow(this.mousemoveX, true);
      }
    },

    /**
     * @Date: 2021-01-20 19:32:39
     * @Desc: 转发窗口时间轴的事件
     */
    triggerClickWindowTimeSegments(data, index, item) {
      this.$emit("click_window_timeSegments", data, index, item);
    },

    /**
     * @Date: 2021-01-21 09:58:17
     * @Desc: 设置分辨率
     */
    setZoom(index) {
      this.currentZoomIndex = index;
      this.clearCanvas(this.width, this.height);
      // this.startTimestamp = this.currentTime - this.totalMS / 2; // 当前时间-新的时间范围的一半
      this.draw();
    },

    /**
     * @Date: 2021-01-21 10:15:30
     * @Desc: 切换窗口时间轴的选中
     */
    toggleActive(index) {
      this.windowListInner.forEach(item => {
        item.active = false;
      });
      this.windowListInner[index].active = true;
      this.$emit("change_window_time_line", index, this.windowListInner[index]);
    },

    /**
     * @Date: 2021-01-21 10:47:28
     * @Desc: 要观察的时间点，会返回该时间点的实时位置，你可以根据该位置来设置一些你的自定义元素，位置为相对于浏览器可视窗口的位置
     */
    watchTime(time, callback, windowTimeLineIndex) {
      if (!time || !callback) {
        return;
      }
      this.watchTimeList.push({
        time: typeof time === "number" ? time : new Date(time).getTime(),
        callback,
        windowTimeLineIndex:
          typeof windowTimeLineIndex === "number" ? windowTimeLineIndex - 1 : -1
      });
    },

    /**
     * @Date: 2021-01-21 13:36:37
     * @Desc: 窗口时间轴滚动
     */
    onWindowListScroll() {
      this.updateWatchTime();
    },

    /**
     * @Date: 2021-01-21 13:40:53
     * @Desc: 尺寸重适应
     */
    onResize() {
      this.init();
      this.draw();
      try {
        this.$refs.WindowListItem.forEach(item => {
          item.init();
        });
      } catch (error) {
        console.log(error);
      }
    },
    /**
     * 处理时间秒
     */
    formatDuration(stime) {
      // 确保输入的是非负整数
      const totalSeconds = Math.max(0, parseInt(stime));
      // 计算小时、分钟和秒数
      const hours = Math.floor(totalSeconds / 3600);
      const minutes = Math.floor((totalSeconds % 3600) / 60);
      const seconds = totalSeconds % 60;

      // 格式化输出，确保两位数显示
      const padWithZero = num => num.toString().padStart(2, "0");

      return `${padWithZero(hours)}:${padWithZero(minutes)}:${padWithZero(
        seconds
      )}`;
    },

    // 时间轴点击事件
    onCanvasClick(...args) {
      this.$emit("click_timeline", ...args);
    }
  }
};
</script>

<style lang="scss" scoped>
.timeLineContainer {
  width: 100%;
  height: 100%;
  cursor: pointer;
  display: flex;
  flex-direction: column;

  .canvas {
    flex-grow: 0;
    flex-shrink: 0;
  }

  .windowList {
    width: 100%;
    height: 100%;
    overflow: auto;
    overflow-x: hidden;
    border-top: 1px solid rgba(153, 153, 153, 1);
    display: flex;
    flex-direction: column;

    &::-webkit-scrollbar {
      display: none;
    }
  }
}
</style>